package com.yjhh.scala

/**
  * Scala类型系统编程实战：
  * 1.Scala的类和方法、函数都可以是泛型，在Spark源码中到处可以看见类和方法的泛型，在实际实例化的时候置顶具体的类型，
  *    例如：Spark最核心、最基础、最重要的抽象数据结构RDD里关于RDD的类的定义是泛型的，RDD的几乎所有的方法的定义也都是泛型的，
  *    之所以这么做，是因为RDD会派生很多子类，通过子类适配了各种不同的数据源以及业务逻辑的操作
  * 2.关于对类型边界的界定，分为上边界和下边界
  *   上边界：表达了泛型的类型必须是某种类型或者某种类的子类，语法为<:
  *   下边界：表达了泛型的类型必须是某种类的父类，语法为>:
  * 3.View Bounds,可以进行某种神秘的转化，把你的类型可以在没有知觉的情况下转化为目标类型，其实你可以任务View Bounds是
  *   上边界和下边界的加强补充版本，例如在SparkContent中有T <% Writeable的方式的代码，这个代码所表达的是T必须是Writeable类型的，但
  *   是T又没有直接继承自Writable接口，此时就需要通过“implicit”的方式来实现这个功能
  * 4.T:ClassTag,例如Spark源码中的RDD class RDD[T:ClassTag]这个其实也是一种类型转换系统，只是在编译的时候类型信息不够，
  *   需要借助于JVM的runtime来通过运行时信息获取完整的类型信息，这在Spark中是非常重要的，因为Spark的程序的编程和运行是区分了Driver和
  *   Executor的，只是在运行的时候在知道完整的类型信息。
  * 5.逆变和协变：-T（子《-父）和+T（子-》父）
  * 6.Context Bounds ,T:Ordering这种语法必须能够变成Ordering[T]这种方式
  */
class Maximum[T:Ordering](val x:T,val y:T){
  def bigger(implicit ord : Ordering[T])={
    if(ord.compare(x,y) > 0) x else y
  }
}

class Enginer
class Expert extends Enginer

class Meeting[-T]

class Animal[T](val species: T) {

  def getAnimal(species: T): T = species

}

class Person(val name : String){
  def talk(person:Person): Unit ={
    println(this.name+" :  "+person.name)
  }
}

class Worker(name:String) extends Person(name)

class Club[T <: Person](p1:T,p2:T){
  def comunicate = p1.talk(p2)
}

class Dog(val name:String)

class Club2[T <% Person](p1:T,p2:T){
  def comunicate = p1.talk(p2)
}

object HelloScalatypeSystem {

  def main(args: Array[String]): Unit = {

    implicit def dog2Person(dog:Dog) = new Person(dog.name)

    val p = new Person("Scala")
    val w = new Worker("Spark")
    val dog = new Dog("xiaohuang")
    val c = new Club(p,w)
    val d = new Club2[Person](dog,p)
    c.comunicate
    d.comunicate

    //逆变，专家能参加的，工程师就能参加
    val expert = new Meeting[Expert]
    participateMeeting(expert)

    val enginer = new Meeting[Enginer]
    participateMeeting(enginer)

    val maximum = new Maximum(2,4)
    println(maximum.bigger)
  }

  def participateMeeting(meeting:Meeting[Expert]): Unit ={
    println("Welcome")
  }

}
